package com.dreamcode.anfeedreader.utils;

import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import com.dreamcode.anfeedreader.modelClass.FeedItem;




/* Usage:
RssParser rp = new RssParser("<RSS Feed URL>");
rp.parse();
RssFeed feed = rp.getFeed();

// Listing all categories & the no. of elements in each category
if (feed.getCategory() != null)
    {
     System.out.println("Category List: ");
     for (String category : feed.getCategory().keySet())
     {
      System.out.println(category
        + ": "
        + ((ArrayList<FeedItem>)feed.getCategory().get(category)).size());
     }
    }

// Listing all items in the feed
for (int i = 0; i < feed.getItems().size(); i++)
     System.out.println(feed.getItems().get(i).getTitle());
 */
 

public class RssParser extends DefaultHandler
{  
    private String        urlString;
    private RssFeed       rssFeed;
    private StringBuilder text;
    private FeedItem          item;
   
    public RssParser(String url)
    {
        this.urlString = url;
        this.text = new StringBuilder();
    }
   
    public void parse()
    {
        InputStream urlInputStream = null;
        SAXParserFactory spf = null;
        SAXParser sp = null;
       
        try
        {
            URL url = new URL(this.urlString);
            urlInputStream = url.openConnection().getInputStream();          
            spf = SAXParserFactory.newInstance();
            XMLReader reader = null;
            if (spf != null)
            {
                sp = spf.newSAXParser();
//                sp.parse(urlInputStream, this);
                reader = sp.getXMLReader();
                reader.setContentHandler(this);
                reader.parse(new InputSource(urlInputStream));
            }
        }

        /*
         * Exceptions need to be handled
         * MalformedURLException
         * ParserConfigurationException
         * IOException
         * SAXException
         */
       
        catch (Exception e)
        {
            System.out.println("Exception: " + e);
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (urlInputStream != null) urlInputStream.close();
            }
            catch (Exception e) {}
        }
    }

    public RssFeed getFeed()
    {
        return (this.rssFeed);
    }
   
    public void startElement(String uri, String localName, String qName,
            Attributes attributes)
    {
        if (localName.equalsIgnoreCase("channel"))
            this.rssFeed = new RssFeed();
        else if (localName.equalsIgnoreCase("item") && (this.rssFeed != null))
        {
            this.item = new FeedItem();
            this.rssFeed.addItem(this.item);
        }
    }
   
    public void endElement(String uri, String localName, String qName)
    {
        if (this.rssFeed == null)
            return;
        
        if (localName.equalsIgnoreCase("item"))
            this.item = null;
        
        else if (localName.equalsIgnoreCase("title"))
        {
            if (this.item != null) this.item.setTitle(this.text.toString().trim());
            else this.rssFeed.title = this.text.toString().trim();
        }       
       
        else if (localName.equalsIgnoreCase("link"))
        {
            if (this.item != null) this.item.setLink(this.text.toString().trim());
            else this.rssFeed.link = this.text.toString().trim();
        }
       
        else if (localName.equalsIgnoreCase("description"))
        {
            if (this.item != null) this.item.setDescription(this.text.toString().trim());
            else this.rssFeed.description = this.text.toString().trim();
        }
        
        else if (localName.equalsIgnoreCase("pubDate") && (this.item != null))
            this.item.setPubDate(this.text.toString().trim());
        this.text.setLength(0);
    }
   
    public void characters(char[] ch, int start, int length)
    {
        this.text.append(ch, start, length);
    }
   
    public static class RssFeed
    {
        public  String title;
        public  String description;
        public  String link;
       
        private LinkedList <FeedItem> items;
        private HashMap <String, List <FeedItem>> category;

        public void addItem(FeedItem item)
        {
            if (this.items == null)
                this.items = new LinkedList<FeedItem>();
            this.items.add(item);
        }
       
        public void addItem(String category, FeedItem item)
        {
            if (this.category == null)
                this.category = new HashMap<String, List<FeedItem>>();
            if (!this.category.containsKey(category))
                this.category.put(category, new LinkedList<FeedItem>());
            this.category.get(category).add(item);
        }
        
        public List<FeedItem> getItems() {
          return items;
        }
        
        public void setItems(List<FeedItem> items) {
          this.items = (LinkedList<FeedItem>) items;
        }
        
        public HashMap<String, List<FeedItem>> getCategory() {
          return category;
        }
        
        public void setCategory(HashMap<String, List<FeedItem>> category) {
          this.category = category;
        }
    }
   
}